package com.example.excel;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.annotation.PostConstruct;

import org.apache.commons.lang3.StringUtils;
import org.docx4j.TraversalUtil;
import org.docx4j.convert.in.xhtml.XHTMLImporterImpl;
import org.docx4j.finders.ClassFinder;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
import org.docx4j.openpackaging.parts.WordprocessingML.StyleDefinitionsPart;
import org.docx4j.wml.Styles;
import org.docx4j.wml.Tbl;
import org.docx4j.wml.TblWidth;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.nodes.Entities;
import org.jsoup.select.Elements;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
import com.deepoove.poi.config.Configure.ELMode;
import com.deepoove.poi.config.ConfigureBuilder;
import com.deepoove.poi.data.PictureRenderData;
import com.deepoove.poi.policy.RenderPolicy;

/**
 * 基于poi-tl的导出工具类
 * @author liuyake
 *
 * 2018-11-21
 */
@Component
public class PoiTlExportUtil {

	@Autowired
    Environment envr;
	
	@Autowired
	static Environment env;
	
	@PostConstruct
	void init() {
		env = envr;
	}
	
	/**
	 * 渲染模版文件(默认语法)
	 * @param customPolicies
	 * @param data
	 * @param templateFile
	 * @param destFile
	 */
	public static void renderTemplate(Map<String,RenderPolicy> customPolicies, Object data, String templateFile, String destFile) {
		ConfigureBuilder builder = Configure.newBuilder();
		//初始化配置，设定语法 ${obj.name}
		Configure config = builder.buildGramer("${", "}").build();
		//增加自定义的特殊符号渲染插件
		builder.addPlugin('<', new SymbolRenderPolicy());
		//添加自定义配置
		for(String key : customPolicies.keySet()) {
			config.customPolicy(key, customPolicies.get(key));	
		}
		// 渲染数据
		XWPFTemplate template = null;
		// 输出文件
		FileOutputStream out = null;
		try {
			template = XWPFTemplate.compile(templateFile, config).render(data);
			out = new FileOutputStream(destFile);
			template.write(out);
			out.flush();
			out.close();
			template.close();
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			if(out!=null) {
				try {
					out.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if(template!=null) {
				try {
					template.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	
	
	/**
	 * 渲染模版文件(springEl语法)
	 * @param config
	 * @param data
	 * @param templateFile
	 * @param destFile
	 */
	public static void renderTemplateSpEl(Map<String,RenderPolicy> customPolicies, Object data, String templateFile, String destFile) {
		ConfigureBuilder builder = Configure.newBuilder();
		builder.setElMode(ELMode.SPEL_MODE);
		//初始化配置，设定语法 ${obj.name}
		Configure config = builder.buildGramer("${", "}").build();
		//增加自定义的特殊符号渲染插件
		builder.addPlugin('<', new SymbolRenderPolicy());
		//添加自定义配置
		for(String key : customPolicies.keySet()) {
			config.customPolicy(key, customPolicies.get(key));	
		}
		// 渲染数据
		XWPFTemplate template = null;
		// 输出文件
		FileOutputStream out = null;
		try {
			template = XWPFTemplate.compile(templateFile, config).render(data);
			out = new FileOutputStream(destFile);
			template.write(out);
			out.flush();
			out.close();
			template.close();
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			if(out!=null) {
				try {
					out.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if(template!=null) {
				try {
					template.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	
	
	
	/**
	 * 处理html类型的内容
	 * 1、获取html中的图片
	 * 2、把html转换成可识别的图片标签,即${@imgId}
	 * 3、把html转为docx文档
	 * 4、把生成的docx文档当作单独文件等待合并到整个文档中
	 * @param html
	 * @param imgList
	 * @param wordList
	 * @return
	 */
	public static String processHtmlContent(String html,List<PictureRenderData> imgList,List<String> wordList) {
		if(null == html) {
			html = "";
		}
		imgList.addAll(PoiTlExportUtil.getImageFromHtml(html,400,300));
		String tagHtml = PoiTlExportUtil.changeImageTag(html);
		String wordFile = PoiTlExportUtil.htmlToWord(tagHtml);
		wordList.add(wordFile);
		return wordFile;
	}
	/**
	 * 获取html文本中的图片标签，并把<img src="xxx" />标签转换为 ${@var}导出的语法
	 * @param html
	 * @return
	 */
	public static String changeImageTag(String html) {
		try {
			Document doc = Jsoup.parse(html);
			Elements imgs = doc.getElementsByTag("img");
			for(Element img : imgs) {
				//src="/console/ueditor/ueditorDownload.do?fileName=/ueditor/jsp/upload/image/20181121/1542793555143063151.png"
				String imgSrc = img.attr("src");
				//获取附件id
				String imgId = getImgIdFromPath(imgSrc,"fileName");
				//把img标签转化为poi-tl的标签
				img.after("${@" + imgId + "}");
				img.remove();
			}
			html = doc.html();
			html = cleanHtmlWithParagraph(html);
			return html;
		}catch(Exception e) {
			e.printStackTrace();
		}finally {
			return html;
		}
	}
	
	/**
	 * 清除html样式并保留段落格式
	 * @param html
	 * @return
	 */
	public static String cleanHtmlWithParagraph(String html) {
		//清除样式和脚本
		html = html.replaceAll("<script([\\s\\S]*?)</script>", "");
		html = html.replaceAll("<style([\\s\\S]*?)</style>", "");
		//处理换行
		//html = html.replace("<BR>", "***");
		//html = html.replace("***", "<br/>");
		html = html.replace("\n", "");
		html = html.replace("\r", "");
        //处理标签内样式
		
		
		return html;
	}
	
	/**
	 * 获取html中的图片元素，
	 * 当无法获取图片宽度时会使用默认高度和宽度
	 * @param html
	 * @param width
	 * @param height
	 * @return
	 */
	public static List<PictureRenderData> getImageFromHtml(String html,int width,int height) {
		List<PictureRenderData> list = new ArrayList<PictureRenderData>();
		try {
			Document doc = Jsoup.parse(html);
			Elements imgs = doc.getElementsByTag("img");
			for(Element ele : imgs) {
				//获取图片高度和宽度
				int widthAttr = Integer.valueOf(getNumbers(ele.attr("width")==null?"0":ele.attr("width")));
				int heightAttr = Integer.valueOf(getNumbers(ele.attr("height")==null?"0":ele.attr("height")));
				if(widthAttr==0) {
					widthAttr = width;
				}
				if(heightAttr==0) {
					heightAttr = height;
				}
				String imgSrc = ele.attr("src");
				String imgPath = imgSrc.substring(imgSrc.indexOf("fileName=")+9, imgSrc.length());
				imgPath = getFileRootPath() + "/" + imgPath;
				PictureRenderData data = new PictureRenderData(widthAttr,heightAttr,imgPath);
				list.add(data);
			}
		}catch(Exception e) {
			e.printStackTrace();
		}finally {
			return list;
		}
	}
	
	/**
	 * 根据参数名从src中获取img的id
	 * @param imgSrc
	 *  @param paramName
	 * @return
	 */
	public static String getImgIdFromPath(String imgSrc,String paramName) {
		String imgPath = imgSrc;
		if(paramName!=null&&!"".equals(paramName)) {
			imgPath = imgSrc.substring(imgSrc.indexOf(paramName+"=")+paramName.length()+1, imgSrc.length());
		}
		String imgId = imgPath.substring(imgPath.lastIndexOf("/")+1,imgPath.length());
		if(imgId.lastIndexOf(".")>0) {
			imgId = imgId.substring(0,imgId.lastIndexOf("."));
		}
		return imgId;
	}
	
	/**
	 * html转word
	 * @param html
	 */
	public static String htmlToWord(String html) {
		String wordFile = null;
		try {
			//wordFile = "D:"+"/" + UUID.randomUUID().toString()+".docx";
			wordFile = getFileRootPath() +File.separator+"temp"+File.separator+ UUID.randomUUID().toString();
			Document doc = Jsoup.parse(html);
			//把html的一些不规范语法强制转换为xhtml规范化语法，避免转docx过程中出错
			doc.outputSettings().syntax(Document.OutputSettings.Syntax.xml).escapeMode(Entities.EscapeMode.xhtml);
            WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.createPackage();
            XHTMLImporterImpl XHTMLImporter = new XHTMLImporterImpl(wordMLPackage);
            wordMLPackage.getMainDocumentPart().getContent().addAll(XHTMLImporter.convert(doc.html(),null));
            //处理默认样式，默认会把word中的标题改为蓝色
            StyleDefinitionsPart stylePart = wordMLPackage.getMainDocumentPart().getStyleDefinitionsPart();
            Styles styles = stylePart.getJaxbElement();
            styles.setLatentStyles(null);
            styles.setDocDefaults(null);
            styles.getStyle().clear();
            //处理表格样式，禁用单元格间距
            MainDocumentPart documentPart = wordMLPackage.getMainDocumentPart();
            ClassFinder finder = new ClassFinder(Tbl.class);
            new TraversalUtil(documentPart.getContent(), finder);
            for(int i=0;i<finder.results.size();i++) {
            	Tbl table_selected =  (Tbl) finder.results.get(i);
            	TblWidth cellSpacing = new TblWidth();
            	cellSpacing.setW(BigInteger.valueOf(0));
            	table_selected.getTblPr().setTblCellSpacing(null);
            }
            wordMLPackage.save(new File(wordFile));
		}catch(Exception e) {
			e.printStackTrace();
		}
		return wordFile;
	}
	
	/**
	 * 获取文件根目录
	 * @return
	 */
	public static String getFileRootPath() {
		String root = null;
		if(env!=null) {
			root = env.getProperty("localFile.root");
		}
		if(StringUtils.isEmpty(root)) {
			String userDir = System.getProperty("user.dir");
			root = userDir+File.separator+"filesystem";
		}
		return root;
	}
	
	/**
	 * 获取数字
	 * @param content
	 * @return
	 */
	public static String getNumbers(String content) {
		Pattern pattern = Pattern.compile("\\d+");
		Matcher matcher = pattern.matcher(content);
		while (matcher.find()) {
			return matcher.group(0);
		}
		return "0";
	}
	
	public static void main(String[] args) {
		String html = "<html>werwer<img src ='/showImg.do?fileName=/image/20181121/1542793555143063151.png' />sefasdfasdfasdf"
				+ "<img src ='/showImg.do?fileName=/image/20181121/1542793555143063151.png' />erwer</html>";
		//changeImageTag(new ArrayList(),html);
		htmlToWord("<table border=1 width=500 height=500><tr><td>12312</td><td>中文</td></tr><tr><td>12312</td><td>英文</td></tr><tr><td colspan=2><p>sdfsadfasfd<br>sdfsdf</td></tr></table>");
		System.out.println(getNumbers("23px"));
	}
}
